package top.xia17.plugins.fast.common.database.jpa.nsql;


import top.xia17.plugins.fast.common.utils.ObjArray2EntityUtil;

import jakarta.persistence.Query;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 原生SQL 执行器
 * @author xia17
 * @date 2020/7/15 9:17
 */
public class NativeQueryActuator {

    public NativeQueryActuator(Query query, String[] result) {
        this.query = query;
        this.result = result;
    }

    public NativeQueryActuator(Query query) {
        this.query = query;
        this.result = null;
    }

    /**
     * Jpa 原生查询
     */
    private final Query query;

    /**
     * 结果转换列明数组
     */
    private final String[] result ;


    /**
     * 执行，返回结果为List<Object[]>
     * @return List<Object[]>
     */
    public List<Object[]> executeForList(){
        return this.query.getResultList();
    }

    /**
     * 执行，返回结果为List<Object[]>
     * @return Object[]
     */
    public Object[] executeForOne(){
        return (Object[]) this.query.getSingleResult();
    }

    /**
     * 执行，返回单个对象 用于Count ， 或者其他只查询一行一列时使用。
     * @return Object
     */
    public Object executeForSingle(){
        return this.query.getSingleResult();
    }

    /**
     * 执行，返回结果为List<Map<String,Object>
     * @return List<Map<String,Object>
     */
    public List<Map<String,Object>> getResultListForMap(){
        List<Object[]> list = this.executeForList();
        return list.stream()
                .map(this::arrayToMap)
                .collect(Collectors.toList());
    }

    /**
     * 执行，返回结果为List<T>
     * @param <T> 转换的实体类
     * @param function 将 Object[] 转换为 T 实体 的函数
     * @return List<T>
     */
    public<T> List<T> getResultListForEntity(Function<Object[],T> function){
        List<Object[]> list = this.executeForList();
        return list.stream()
                .map(function)
                .collect(Collectors.toList());
    }

    /**
     * 执行 ，返回结果为List<T>
     *     使用QueryResultHelp 映射成实体
     * @param clz /
     * @param sign /
     * @param <T> /
     * @return /
     */
    public<T> List<T> getResultListForEntity(Class<T> clz , int sign){
        return ObjArray2EntityUtil.mapping(this.executeForList(),clz,sign);
    }

    /**
     * 执行 ，返回结果为List<T>
     *     使用QueryResultHelp 映射成实体
     * @param clz /
     * @param <T> /
     * @return /
     */
    public<T> List<T> getResultListForEntity(Class<T> clz){
        return getResultListForEntity(clz,0);
    }


    /**
     * 根据result[] 列名数组将 Object[] 转化为Map
     * @param os Object[]
     * @return map
     */
    private Map<String,Object> arrayToMap(Object[] os){
        if (result == null){
            throw new RuntimeException("映射成Map时没有提供对应字段名数组 result[] !");
        }
        HashMap<String, Object> res = new HashMap<>(os.length);
        if (os.length!=result.length){
            throw new RuntimeException("返回的列数与配置的列数不一致！");
        }
        for (int i = 0; i < result.length; i++) {
            res.put(result[i],os[i]);
        }
        return res;
    }




}
